//go:build !notmpfiles
// +build !notmpfiles

// Package collector 包含所有用于收集和导出系统指标的单独收集器。
package collector

import (
	"fmt"
	"log/slog"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/prometheus/client_golang/prometheus"
)

// LogicDiskInfo 表示逻辑磁盘设备的信息
type LogicDiskInfo struct {
	// DeviceID 设备标识符
	DeviceID string
	// Controller 控制器名称
	Controller string
	// RaidLevel RAID级别 (如 RAID0, RAID1, RAID5, RAID10等)
	RaidLevel string
	// Size 磁盘大小
	Size string
	// State 磁盘状态 (如 Optimal, Degraded等)
	State string
	// NumberOfDrives 包含的物理磁盘数量
	NumberOfDrives int
	// Info 其他信息映射
	Info map[string]string
}

// raidLogicDiskCollector 结构体定义了 RAID 逻辑磁盘收集器
type raidLogicDiskCollector struct {
	desc   *prometheus.Desc
	logger *slog.Logger
}

// 注册到页面
func init() {
	// 注册 RAID 逻辑磁盘收集器到页面
	registerCollector("raidlogicdisk", defaultEnabled, NewRaidLogicDiskCollector)
}

// NewRaidLogicDiskCollector 创建一个新的 RAID 逻辑磁盘收集器
func NewRaidLogicDiskCollector(logger *slog.Logger) (Collector, error) {
	desc := prometheus.NewDesc(
		prometheus.BuildFQName(namespace, "raid", "logic_disk_number_of_drives"),
		"Number of physical drives in the logic disk with labels for disk info.",
		[]string{"disk", "controller", "raid_level", "size", "state"}, nil,
	)

	return &raidLogicDiskCollector{
		desc:   desc,
		logger: logger,
	}, nil
}

// Update 实现 Collector 接口，返回检测到的 RAID 逻辑磁盘信息
func (c *raidLogicDiskCollector) Update(ch chan<- prometheus.Metric) error {
	// 使用 raidtool 获取 RAID 逻辑磁盘信息
	c.logger.Info("开始更新 RAID 逻辑磁盘指标")

	// 获取当前执行文件的路径
	execPath, err := os.Executable()
	if err != nil {
		c.logger.Error("获取执行文件路径出错", "error", err)
		return err
	}

	// 获取执行文件所在的目录
	execDir := filepath.Dir(execPath)

	// 构造 raidtool 的绝对路径
	raidtoolPath := filepath.Join(execDir, "bin", "raidtool")

	// 检查 raidtool 文件是否存在
	if _, err := os.Stat(raidtoolPath); os.IsNotExist(err) {
		c.logger.Error("raidtool 文件不存在", "path", raidtoolPath, "error", err)
		return fmt.Errorf("raidtool 文件不存在: %s", raidtoolPath)
	}

	output, err := exec.Command(raidtoolPath, "getLdList").Output()
	if err != nil {
		c.logger.Error("执行命令出错", "error", err)
		return err
	}

	// 将输出结果保存到文件
	logFile := filepath.Join(execDir, "logic_disk_result.log")
	err = os.WriteFile(logFile, output, 0644)
	if err != nil {
		c.logger.Error("保存文件出错", "error", err)
		return err
	}

	// 检测并解析日志文件格式
	logicDisks, err := c.detectLogFormat(logFile)
	if err != nil {
		// 记录解析日志文件失败的错误
		c.logger.Error("解析 RAID 日志文件失败", "error", err)
		return err
	}

	// 添加调试信息
	c.logger.Info("解析完成", "磁盘数量", len(logicDisks))

	// 处理每个逻辑磁盘并生成指标
	for i, disk := range logicDisks {
		c.logger.Info("处理磁盘", "索引", i, "设备ID", disk.DeviceID, "RAID级别", disk.RaidLevel, "状态", disk.State)

		// 发送物理磁盘数量指标，所有逻辑磁盘信息都在标签中
		ch <- prometheus.MustNewConstMetric(
			c.desc,
			prometheus.GaugeValue,
			float64(disk.NumberOfDrives),
			disk.DeviceID,
			disk.Controller,
			disk.RaidLevel,
			disk.Size,
			disk.State,
		)
	}

	c.logger.Info("完成 RAID 逻辑磁盘指标更新")
	return nil
}

// detectLogFormat 检测日志文件格式并选择合适的解析函数
func (c *raidLogicDiskCollector) detectLogFormat(filename string) ([]LogicDiskInfo, error) {
	data, err := os.ReadFile(filename)
	if err != nil {
		return nil, fmt.Errorf("读取日志文件失败: %w", err)
	}

	content := string(data)

	// 使用 Info 级别确保日志输出
	c.logger.Info("开始检测日志格式", "文件大小", len(content))

	// 根据文件内容检测日志格式
	switch {
	case strings.Contains(content, "Controllers found"):
		// arcconf 日志格式
		c.logger.Info("检测到 Arcconf 日志格式")
		return ParseArcconfLogicDiskLog(filename, c.logger)
	case strings.Contains(content, "CLI Version"):
		// storcli 日志格式
		c.logger.Info("检测到 StorCLI 日志格式")
		return ParseStorcliLogicDiskLog(filename, c.logger)
	case strings.Contains(content, "Virtual Drive"):
		// MegaCLI 日志格式
		c.logger.Info("检测到 MegaCLI 日志格式")
		return ParseMegaCLILogicDiskLog(filename, c.logger)
	default:
		// 默认尝试所有解析器
		c.logger.Info("使用默认解析器尝试解析")
		// 可以在这里添加尝试所有解析器的逻辑
		return ParseMegaCLILogicDiskLog(filename, c.logger)
	}
}
